package com.sinooceangroup.capital.gateway.filter;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 自定义GlobalFilter， 系统启动自动加载，作用于全局，不需要进行配置。
 * 实现步骤：
 *      1. 实现接口 {@link GlobalFilter} 和 {@link Ordered}：
 *          a) 重写GlobalFilter接口的filter方法： 对Request和Response做加工处理。
 *              chain.filter(exchange)调用前的代码是Pre处理
 *              chain.filter(exchange).then() 中处理的是Post处理
 *          b) 重写Ordered接口的getOrder： 该方法返回一个整数，数字越小表示在SpringBoot启动时该类的实例在Spring容器中加载的顺序越靠前
 *      2. 添加注解 {@link Component}： SpringBoot 启动时会自动扫描该类并实例化-->添加到Spring容器中-->作用于所有请求
 * @author: Leo.Wang, adwyxx@qq.com
 * @date: 2020/7/22 18:01
 */
@Component
public class AuthorizeGlobalFilter implements GlobalFilter, Ordered {
    private static final String AUTHORIZE_TOKEN = "token";
    /**
     * url匹配器
     */
    private AntPathMatcher pathMatcher = new AntPathMatcher();

    /**
     * 忽略token认证的api路由
     */
    @Value("#{'${authorize.ignore-routes}'.split(',')}")
    private String[] ignoreRoutes;

    /***
     * Token 认证处理
     * @param exchange
     * @param chain : filter 链
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        boolean isIgnored = false;
        String route =exchange.getRequest().getPath().value();
        for (String ignored : ignoreRoutes) {
            if (pathMatcher.match(ignored,route)) {
                isIgnored = true; // 白名单
                break;
            }
        }
        if(isIgnored){
            return chain.filter(exchange);
        }

        HttpHeaders headers = request.getHeaders();
        String token = headers.getFirst(AUTHORIZE_TOKEN);
        if (token == null) {
            token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
        }

        ServerHttpResponse response = exchange.getResponse();
        if (StringUtils.isEmpty(token)) {
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            //结束请求，直接返回Response
            return response.setComplete();
        }
        //进入下一个Filter
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }
}
